package account

import (
    "context"
    "encoding/base64"
    "fmt"

    "github.com/gin-gonic/gin"
    "gorm.io/gorm"
    "iip/account/model"
    "iip/account/account_type"
    dict "iip/dictionary/model"
    "iip/lib"
    "libgo/security/webpass"
)


func (s *Account) Register(c *gin.Context) {
    req := &struct {
        Name      string `form:"name"        json:"name"        binding:"required"`
        Pass      string `form:"pass"        json:"pass"        binding:"required"`
        Phone     string `form:"phone"       json:"phone"       binding:"required"`
        Email     string `form:"email"       json:"email"       binding:""`
        CompanyID int64  `form:"company_id"  json:"company_id"  binding:""`
        Avatar    string `form:"avatar"      json:"avatar"      binding:""`
        WXOpenID  string `form:"wx_openid"   json:"wx_openid"   binding:""`
    }{}
    if err := c.ShouldBind(req); err != nil {
        lib.JsonError(c, err.Error())
        return
    }
    s.logger.Info("账号注册", req)


    acc := &model.Account{}
    acc.ID = s.idgen.NextID()
    acc.Name = req.Name
    acc.Phone = req.Phone
    acc.Email = req.Email
    acc.State = account_type.StateActive
    acc.RegisterIP = c.ClientIP()


    auth := &model.AccountAuth{}
    auth.ID = s.idgen.NextID()
    auth.AccountID = acc.ID
    auth.Type = account_type.AuthTypePhonePass
    auth.IDentifier = acc.Name
    auth.Credential = webpass.MakePasswordHash(req.Pass)

    var com *dict.DictCompany
    var err error
    if req.CompanyID != 0 {

        com, err = s.dict.GetCompanyByID(req.CompanyID)
        if err != nil {
            acc.CompanyID = 0
        } else {
            acc.CompanyID = com.ID
        }
    }

    role, err := s.GetRoleByName("未授权用户")
    if err != nil {
        role = nil
    }

    err = s.gorm().Transaction(func(tx *gorm.DB) error {

        if err := tx.Create(acc).Error; err != nil {
            return err
        }

        if err := tx.Create(auth).Error; err != nil {
            return err
        }

        if role != nil {
            acc_role := &model.AccountRole{}
            acc_role.ID = s.idgen.NextID()
            acc_role.AccountID = acc.ID
            acc_role.RoleID = role.ID
            if err := tx.Create(acc_role).Error; err != nil {
                return err
            }
        }
        return nil
    })
    if err != nil {
        s.logger.Error(err)
        lib.JsonError(c, err.Error())
        return
    }


    acc_log := &model.AccountLog{}
    acc_log.ID = s.idgen.NextID()
    acc_log.Type = account_type.AccountRegister
    acc_log.AccountID = acc.ID
    acc_log.AccountName = acc.Name
    acc_log.IP = c.ClientIP()
    if err := s.gorm().Create(acc_log).Error; err != nil {
        s.logger.Error(err)
    }
    lib.JsonData(c, s.account_detail(acc))
}


func (s *Account) WXMiniRegister(c *gin.Context) {
    req := &struct {
        Name      string `form:"name"        json:"name"        binding:"required"`
        Pass      string `form:"pass"        json:"pass"        binding:""`
        Phone     string `form:"phone"       json:"phone"       binding:"required"`
        Email     string `form:"email"       json:"email"       binding:""`
        CompanyID int64  `form:"company_id"  json:"company_id"  binding:""`
        Avatar    string `form:"avatar"      json:"avatar"      binding:""`
        WXOpenID  string `form:"wx_openid"   json:"wx_openid"   binding:"required"`
    }{}
    if err := c.ShouldBind(req); err != nil {
        lib.JsonError(c, err.Error())
        return
    }
    s.logger.Info("微信小程序账号注册", req)


    if _, err := s.GetAccountByWXOpenID(req.WXOpenID); err == nil {
        err1 := fmt.Errorf("微信openid[%s]已经注册", req.WXOpenID)
        s.logger.Info(err1)
        lib.JsonError(c, err1.Error())
        return
    }


    acc := &model.Account{}
    acc.ID = s.idgen.NextID()
    acc.Name = req.Name
    acc.Phone = req.Phone
    acc.Email = req.Email
    acc.State = account_type.StateActive
    acc.RegisterIP = c.ClientIP()
    acc.WxOpenid = req.WXOpenID


    auth := &model.AccountAuth{}
    auth.ID = s.idgen.NextID()
    auth.AccountID = acc.ID
    auth.Type = account_type.AuthTypeWXOpenID
    auth.IDentifier = acc.WxOpenid
    auth.Credential = acc.WxOpenid

    var com *dict.DictCompany
    var err error
    if req.CompanyID != 0 {

        com, err = s.dict.GetCompanyByID(req.CompanyID)
        if err != nil {
            acc.CompanyID = 0
        } else {
            acc.CompanyID = com.ID
        }
    }

    role, err := s.GetRoleByName("未授权用户")
    if err != nil {
        role = nil
    }

    err = s.gorm().Transaction(func(tx *gorm.DB) error {

        if err := tx.Create(acc).Error; err != nil {
            return err
        }

        if err := tx.Create(auth).Error; err != nil {
            return err
        }

        if role != nil {
            acc_role := &model.AccountRole{}
            acc_role.ID = s.idgen.NextID()
            acc_role.AccountID = acc.ID
            acc_role.RoleID = role.ID
            if err := tx.Create(acc_role).Error; err != nil {
                return err
            }
        }
        return nil
    })
    if err != nil {
        s.logger.Error(err)
        lib.JsonError(c, err.Error())
        return
    }


    acc_log := &model.AccountLog{}
    acc_log.ID = s.idgen.NextID()
    acc_log.Type = account_type.AccountRegister
    acc_log.AccountID = acc.ID
    acc_log.AccountName = acc.Name
    acc_log.IP = c.ClientIP()
    if err := s.gorm().Create(acc_log).Error; err != nil {
        s.logger.Error(err)
    }
    lib.JsonData(c, s.account_detail(acc))
}


func (s *Account) SendPhoneVerificationCode() {

}


func (s *Account) Update(c *gin.Context) {
    req := &struct {
        AccID     int64  `form:"id"          json:"id"          binding:"required"`
        Name      string `form:"name"        json:"name"        binding:""`
        Phone     string `form:"phone"       json:"phone"       binding:""`
        Email     string `form:"email"       json:"email"       binding:""`
        CompanyID int64  `form:"company_id"  json:"company_id"  binding:""`
        Avatar    string `form:"avatar"      json:"avatar"      binding:""`
    }{}
    if err := c.ShouldBind(req); err != nil {
        s.logger.Error(err.Error())
        lib.JsonError(c, err.Error())
        return
    }

    acc, err := s.GetAccountByID(req.AccID)
    if err != nil {
        s.logger.Error(err)
        lib.JsonError(c, err.Error())
        return
    }
    if req.Name != "" {
        acc.Name = req.Name
    }
    if req.Phone != "" {
        acc.Phone = req.Phone
    }
    if req.Email != "" {
        acc.Email = req.Email
    }
    if req.Avatar != "" {
        img_buf, err := base64.StdEncoding.DecodeString(req.Avatar)
        if err != nil {
            s.logger.Error(err)
            acc.Avatar = ""
        } else {

            fname, err := s.oss.Store(context.Background(), img_buf)
            if err != nil {
                s.logger.Error(err)
                acc.Avatar = ""
            } else {
                acc.Avatar = fname
            }
        }
    }
    var com *dict.DictCompany
    if req.CompanyID != 0 {
        com, err = s.dict.GetCompanyByID(req.CompanyID)
        if err != nil {
            s.logger.Error(err)
        } else {
            req.CompanyID = com.ID
        }
    }

    if err := s.gorm().Save(acc).Error; err != nil {
        s.logger.Error(err)
        lib.JsonError(c, err.Error())
        return
    }

    s.logger.Info("账号修改成功")
    lib.JsonData(c, s.account_detail(acc))
}


func (s *Account) ChangePassword(c *gin.Context) {
    acc_p, ok := c.Get("acc")
    if !ok {
        panic("not exist")
    }
    acc := acc_p.(*model.Account)
    s.logger.Infof("%s chang password", acc.Name)


    req := &struct {
        OldPass string `form:"old_password"    json:"old_password"       binding:"required"`
        NewPass string `form:"new_password"    json:"new_password"       binding:"required"`
    }{}
    if err := c.ShouldBind(req); err != nil {
        lib.JsonError(c, err.Error())
        return
    }
    s.logger.Info("修改密码", acc.Name)


    auth, err := s.GetAuth(acc.ID, account_type.AuthTypePhonePass)
    if err != nil {
        s.logger.Error(err)
        lib.JsonError(c, err.Error())
        return
    }
    if !webpass.PasswordVerify(req.OldPass, auth.Credential) {
        s.logger.Error("旧密码不匹配")
        lib.JsonError(c, "旧密码错误")
        return
    }

    auth.Credential = webpass.MakePasswordHash(req.NewPass)
    if err := s.gorm().Save(auth).Error; err != nil {
        s.logger.Error(err)
        lib.JsonError(c, err.Error())
        return
    }
    s.logger.Infof("用户%s修改密码成功", acc.Name)
    lib.JsonOK(c)
}


func (s *Account) SysChangePassword(c *gin.Context) {
    req := &struct {
        ID int64 `uri:"id"`
    }{}
    if err := c.ShouldBindUri(req); err != nil {
        s.logger.Error(err.Error())
        lib.JsonError(c, err.Error())
        return
    }

    acc, err := s.GetAccountByID(req.ID)
    if err != nil {
        s.logger.Error(err.Error())
        lib.JsonError(c, err.Error())
        return
    }
    s.logger.Infof("admin chang %s  password", acc.Name)


    req_ := &struct {

        NewPass string `form:"new_password"    json:"new_password"       binding:"required"`
    }{}
    if err := c.ShouldBind(req_); err != nil {
        lib.JsonError(c, err.Error())
        return
    }
    s.logger.Info("修改密码", acc.Name)


    auth, err := s.GetAuth(acc.ID, account_type.AuthTypePhonePass)
    if err != nil {
        s.logger.Error(err)
        lib.JsonError(c, err.Error())
        return
    }
    auth.Credential = webpass.MakePasswordHash(req_.NewPass)
    if err := s.gorm().Save(auth).Error; err != nil {
        s.logger.Error(err)
        lib.JsonError(c, err.Error())
        return
    }
    s.logger.Infof("admin修改用户%s密码成功", acc.Name)
    lib.JsonOK(c)
}


func (s *Account) ForgetPassword(c *gin.Context) {

}


func (s *Account) AccountDetailByID(c *gin.Context) {
    acc_p, ok := c.Get("acc")
    if !ok {
        s.logger.Error("no acc")
        lib.JsonError(c, "no acc")
        return
    }
    acc := acc_p.(*model.Account)

    row, err := s.GetAccountByID(acc.ID)
    if err != nil {
        s.logger.Error(err.Error())
        lib.JsonError(c, err.Error())
        return
    }


    com, err := s.dict.GetCompanyByID(row.CompanyID)
    if err != nil {
        s.logger.Error(err)
        com = nil
    }


    role_list, err := s.GetAccountRoles(row.ID)
    if err != nil {
        s.logger.Error(err)
        role_list = []*model.Role{}
    }

    lib.JsonData(c, &struct {
        model.Account
        Company  *dict.DictCompany `json:"company"`
        RoleList []*model.Role     `json:"role_list"`
    }{
        Account:  *row,
        Company:  com,
        RoleList: role_list,
    })
}


func (s *Account) SysAccountDetailByID(c *gin.Context) {
    req := &struct {
        ID int64 `uri:"id"`
    }{}
    if err := c.ShouldBindUri(req); err != nil {
        s.logger.Error(err.Error())
        lib.JsonError(c, err.Error())
        return
    }

    acc, err := s.GetAccountByID(req.ID)
    if err != nil {
        s.logger.Error(err.Error())
        lib.JsonError(c, err.Error())
        return
    }
    lib.JsonData(c, s.account_detail(acc))
}


func (s *Account) SysAccountPagedList(c *gin.Context) {

    query := &struct {
        Page     int    `form:"page" binding:"required,gte=1" json:"page"`
        PageSize int    `form:"pagesize" binding:"required,gte=1" json:"pagesize"`
        Order    string `form:"order" json:"order"`
    }{}
    if err := c.ShouldBindQuery(query); err != nil {
        s.logger.Error(err.Error())
        lib.JsonError(c, err.Error())
        return
    }
    if query.Order != "asc" && query.Order != "desc" {
        query.Order = "asc"
    }


    var total int64
    if err := s.gorm().Model(&model.Account{}).Count(&total).Error; err != nil {
        s.logger.Error(err.Error())
        lib.JsonError(c, err.Error())
        return
    }

    var acc_list []*model.Account
    if err := s.gorm().Limit(query.PageSize).Offset(query.PageSize * (query.Page - 1)).Order("id " + query.Order).Find(&acc_list).Error; err != nil {
        s.logger.Error(err.Error())
        lib.JsonError(c, err.Error())
        return
    }

    var acc_detail_list []interface{}
    for _, acc := range acc_list {
        acc_detail_list = append(acc_detail_list, s.account_detail(acc))
    }
    s.logger.Info("query account paged list")
    lib.JsonPagedData(c, total, query.Page, query.PageSize, acc_detail_list)
}


func (s *Account) SysAccountCreate(c *gin.Context) {
}


func (s *Account) SysAccountUpdate(c *gin.Context) {
    req := &struct {
        AccID     int64  `form:"id"          json:"id"          binding:"required"`
        Name      string `form:"name"        json:"name"        binding:""`
        Phone     string `form:"phone"       json:"phone"       binding:""`
        Email     string `form:"email"       json:"email"       binding:""`
        CompanyID int64  `form:"company_id"  json:"company_id"  binding:""`
        Avatar    string `form:"avatar"      json:"avatar"      binding:""`
        State     int    `form:"state" json:"state" binding:""`
    }{}
    if err := c.ShouldBind(req); err != nil {
        s.logger.Error(err.Error())
        lib.JsonError(c, err.Error())
        return
    }

    acc, err := s.GetAccountByID(req.AccID)
    if err != nil {
        s.logger.Error(err)
        lib.JsonError(c, err.Error())
        return
    }
    if req.Name != "" {
        acc.Name = req.Name
    }
    if req.Phone != "" {
        acc.Phone = req.Phone
    }
    if req.Email != "" {
        acc.Email = req.Email
    }
    if req.Avatar != "" {
        img_buf, err := base64.StdEncoding.DecodeString(req.Avatar)
        if err != nil {
            s.logger.Error(err)
            acc.Avatar = ""
        } else {

            fname, err := s.oss.Store(context.Background(), img_buf)
            if err != nil {
                s.logger.Error(err)
                acc.Avatar = ""
            } else {
                acc.Avatar = fname
            }
        }
    }
    var com *dict.DictCompany
    if req.CompanyID != 0 {
        com, err = s.dict.GetCompanyByID(req.CompanyID)
        if err != nil {
            s.logger.Error(err)
        } else {
            req.CompanyID = com.ID
        }
    }
    if req.State != 0 {
        acc.State = req.State
    }

    if err := s.gorm().Save(acc).Error; err != nil {
        s.logger.Error(err)
        lib.JsonError(c, err.Error())
        return
    }

    s.logger.Info("账号修改成功")
    lib.JsonData(c, s.account_detail(acc))
}
